/*
	Pulsar engine. Core.
	Internal include file (memory managment). DONT INCLUDE IT from OUTSIDE sources

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#ifndef _PL_MEMORY_INFO_H_
#define _PL_MEMORY_INFO_H_

namespace pl
{

#define PL_MEM_ERROR1(file, line, func, p, size, code)     if (!pl::IAppDebug::callOnMemErr(file, line, func, p, size, code)) PL_BREAK()
#define PL_MEM_ERROR2(p, size, code)                       if (!pl::IAppDebug::callOnMemErr(NULL, 0, NULL, p, size, code)) PL_BREAK()

/**
	Internal debug memory structure
*/
struct _MemHeader
{
	pl_uint16 actualAddressOffset : 12;   // Offset from _MemHeader begin to actually allocated address (usually 0, may be more if alignment required)
	pl_uint16 blockType : 4;              // enum BlockType
	pl_uint16 lineNumber;                 // Line number where allocation occured
	const pl_char* fileName;              // source file name
	pl_uint64 blockSize : 63;             // Size of block in bytes
	pl_uint64 allocBeforeInit : 1;        // 1, if allocation before kernel initialization
	_MemHeader* pNextBlock;               // Next block
	_MemHeader* pPrevBlock;               // Previous block
	const pl_char* funcName;              // Function name
	pl_uint32 allocationIndex : 31;       // Ordering of allocation
	pl_uint32 internalAllocationFlag : 1; // Internal allocation flag
	pl_int32 threadId;                    // Thread of allocation
	pl_uint32 sign1;                      // Overrun signature1
	pl_uint32 sign2;                      // Overrun signature2
};

/*
	Internal memory manager information
*/
struct MemGlobalInfo
{
	CriticalSection *pDebugCs;                // Critical section to handle allocation (NULL - system not inited)
	_MemHeader* pFirstBlock;                  // Head of list
	bool fDisableMalloc;                      // true, if allocations were disabpled
	bool fEnableThreadCheck;                  // true, cross-thread checka are enabled
	bool fInternalAllocations;                // true, if internal allocation mode
	pl_uint16 footerSize;                     // Size of overrun check footer
	pl_uint16 staticAllocAlignment;           // Default alignment for static_malloc()
	pl_uint32 curAllocationIndex;             // Next allocation index
	pl_uint32 allocationOptions;              // Allocation options (see MEMOPTIONS_* defines)
	pl::Vector<pl_uint32, 32> breakIndex;     // Allocation index to break into debugger
	pl::Vector<const void*, 32> breakAddress; // Allocation address to break into debugger
	pl_uint32 nMaxAllowedBlocks;              // Max number of blocks to allocate
	pl_uint32 nMaxAllowedBytes;               // Max number of bytes to allocate
	IGlobalAlloc* iGlobalAlloc;               // Global allocation interfaces

	pl_uint32 nAllocatedBlocks;               // Statistics - n blocks
	pl_uint64 nAllocatedSize;                 // Statistics - total size
};

// Initialize memory manager (internal function, called automatically)
extern bool initMemoryManager();
// Initialize memory manager (internal function, called automatically)
extern void termMemoryManager();

// Initialize frame memory (called automatically)
extern void initMemoryFrame();
// Shutdown frame memory(called automatically)
extern void termMemoryFrame();

extern pl::MemoryError _checkBlock(const void* pUserAddress, int blockType, pl_intptr threadId);
extern void _replaceInfo(const void* pUserAddress, const pl_char*& file, pl_uint32& line, const pl_char*& func);
extern void* _getAllocAddress(void* pUserAddress, size_t& size);
extern void _formatString(pl::String<1024> &str, const _MemHeader* pHdr, bool bIncludeName = true);

extern MemGlobalInfo _memGlobalInfo;

} // namespace pl

#endif // _PL_MEMORY_INFO_H_

//
// End of file 'pulsar_memory_info.h'
//
